package com.sugar.subscribe.course.module.business.service.user;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.sugar.subscribe.course.module.business.controller.app.user.vo.AppBizUserRespVO;
import com.sugar.subscribe.course.module.business.controller.app.user.vo.AppBizUserUpdateReqVO;
import com.sugar.subscribe.course.module.business.controller.app.user.vo.BizUserWechatLoginReqVO;
import com.sugar.subscribe.course.module.business.util.wechat.WeChatLoginUtil;
import com.sugar.subscribe.course.module.business.util.wechat.vo.WeChatOpenIdRespVO;
import com.sugar.subscribe.course.module.system.api.auth.AuthApi;
import com.sugar.subscribe.course.module.system.api.auth.dto.AppAuthDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;

import com.sugar.subscribe.course.module.business.controller.admin.user.vo.*;
import com.sugar.subscribe.course.module.business.dal.dataobject.user.BizUserDO;
import com.sugar.subscribe.course.framework.common.pojo.PageResult;
import com.sugar.subscribe.course.framework.common.util.object.BeanUtils;

import com.sugar.subscribe.course.module.business.dal.mysql.user.BizUserMapper;

import static com.sugar.subscribe.course.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.sugar.subscribe.course.framework.common.util.collection.CollectionUtils.convertList;
import static com.sugar.subscribe.course.module.business.enums.ErrorCodeConstants.*;

/**
 * 用户 Service 实现类
 *
 * @author Ysugar
 */
@Slf4j
@Service
@Validated
public class BizUserServiceImpl implements BizUserService {

    @Resource
    private BizUserMapper bizUserMapper;

    @Resource
    private AuthApi authApi;

    private static final ReentrantLock LOGIN_LOCK = new ReentrantLock(true);

    @Override
    public Long createBizUser(BizUserSaveReqVO createReqVO) {
        // 插入
        BizUserDO bizUser = BeanUtils.toBean(createReqVO, BizUserDO.class);
        bizUserMapper.insert(bizUser);

        // 返回
        return bizUser.getId();
    }

    @Override
    public void updateBizUser(BizUserSaveReqVO updateReqVO) {
        // 校验存在
        getBizUserValidate(updateReqVO.getId());
        // 更新
        BizUserDO updateObj = BeanUtils.toBean(updateReqVO, BizUserDO.class);
        bizUserMapper.updateById(updateObj);
    }

    @Override
    public void deleteBizUser(Long id) {
        // 校验存在
        getBizUserValidate(id);
        // 删除
        bizUserMapper.deleteById(id);
    }

    @Override
        public void deleteBizUserListByIds(List<Long> ids) {
        // 删除
        bizUserMapper.deleteByIds(ids);
        }


    public BizUserDO getBizUserValidate(Long id) {
        BizUserDO user = bizUserMapper.selectById(id);
        if (null == user) {
            throw exception(BIZ_USER_NOT_EXISTS);
        }

        return user;
    }

    @Override
    public BizUserDO getBizUser(Long id) {
        return bizUserMapper.selectById(id);
    }

    @Override
    public PageResult<BizUserDO> getBizUserPage(BizUserPageReqVO pageReqVO) {
        return bizUserMapper.selectPage(pageReqVO);
    }


    // ======================================== 其它 接口 ========================================

    @Override
    public void updateUserCoachInfo(Long userId, Long coachId) {
        bizUserMapper.update(BizUserDO::getId, userId, BizUserDO::getIsCoach, true, BizUserDO::getCoachUserId, coachId);
    }

    @Override
    public String getUserOpenIdByCoachId(Long coachId) {
        BizUserDO user = bizUserMapper.selectOne(BizUserDO::getCoachUserId, coachId);
        if (null == user) {
            throw exception(BIZ_USER_NOT_EXISTS);
        }

        if (StrUtil.isBlank(user.getOpenId()))
            throw exception(BIZ_USER_OPEN_ID_IS_EMPTY_TRANSFER);

        return user.getOpenId();
    }

    // ======================================== APP 接口 ========================================

    @Override
    public AppAuthDTO login(BizUserWechatLoginReqVO loginReqVO) {
        // 根据code换取openid
        WeChatOpenIdRespVO weChatOpenIdRespVO = WeChatLoginUtil.wechatLogin(loginReqVO.getCode());

        // 根据手机号code换取手机号
        String userMobile = WeChatLoginUtil.getUserMobile(loginReqVO.getMobileCode());
        if (StrUtil.isBlank(userMobile))
            throw exception(WX_MOBILE_AUTH_ERROR);

        String openId = weChatOpenIdRespVO.getOpenId();

        try {
            LOGIN_LOCK.lock();
            // 再次查询
            BizUserDO user = bizUserMapper.selectOne(BizUserDO::getOpenId, openId);
            if (null == user){
                user = bizUserMapper.selectOne(BizUserDO::getMobile, userMobile);
                // 创建用户
                if (null == user){
                    // 获取默认头像
                    String avatar = /*configService.getBizConfigByKey(ConfigEnum.USER_DEFAULT_AVATAR, String.class)*/ null;

                    user = new BizUserDO();
                    user.setMobile(userMobile)
                            .setNickname(userMobile)
                            .setOpenId(openId)
                            // 设置默认头像
                            .setAvatar(avatar)
                            .setStatus(true)
                            .setLastLoginTime(LocalDateTime.now());

                    bizUserMapper.insert(user);
                }else if (!openId.equals(user.getOpenId())){ // 判断用户的openid是否与库中的一致
                    throw exception(BIZ_USER_IS_BIND_OTHER_MOBILE);
                }
            }else if (!userMobile.equals(user.getMobile())){ // 判断已存在的用户手机号是否与库中的用户一致
                throw exception(BIZ_USER_IS_BIND_OTHER_WX);
            }

            if (!user.getStatus())
                throw exception(USER_ACCOUNT_FORBIDDEN);

            // 更新用户最后一次登录时间
            bizUserMapper.update(BizUserDO::getId, user.getId(), BizUserDO::getLastLoginTime, LocalDateTime.now());

            AppAuthDTO appAuthDTO = authApi.appLogin(user.getId(), user.getMobile(), false);

            appAuthDTO.setUserInfo(BeanUtils.toBean(user, AppBizUserRespVO.class));
            return appAuthDTO;
        } catch (Throwable e) {
            log.error("用户注册失败：", e);
            throw exception(BIZ_USER_REGISTER_ERROR);
        } finally {
            if (LOGIN_LOCK.isLocked())
                LOGIN_LOCK.unlock();
        }
    }

    @Override
    public void appUpdateUser(AppBizUserUpdateReqVO updateReqVO, Long userId) {
        String avatar = updateReqVO.getAvatar();
        String nickname = updateReqVO.getNickname();
        Integer gender = updateReqVO.getGender();
        String name = updateReqVO.getName();

        if (StrUtil.isNotBlank(avatar) || StrUtil.isNotBlank(nickname) || null != gender || StrUtil.isNotBlank(name))
            bizUserMapper.update(Wrappers.<BizUserDO>lambdaUpdate()
                    .eq(BizUserDO::getId, userId)
                    .set(BizUserDO::getAvatar, avatar)
                    .set(BizUserDO::getNickname, nickname)
                    .set(BizUserDO::getGender, gender)
                    .set(BizUserDO::getName, name));
    }

    @Override
    public AppBizUserRespVO appGetUser(Long userId) {
        return BeanUtils.toBean(getBizUserValidate(userId), AppBizUserRespVO.class);
    }
}